// ***************************************************************************
// CHANGE LOG
//
// ***************************************************************************

#include <p32xxxx.h>
#include <plib.h>
#include "Dac8568C.h"
#include "Spi.h"

/*! \brief Creates a new instance of the DigitalAnalogConverter class.
 *
 * Creates a new instance of the DigitalAnalogConverter class.
 *
 * @param spi Spi device
 * @param referenceVoltage DAC reference voltage
 * @param bitResolution Bit resolution of DAC
 * @param clearPort IO Port used for !Clear
 * @param clearPin IO Pin used for !Clear
 */
Dac8568C::Dac8568C(
									  Spi *spi,
									  float referenceVoltage,
									  unsigned char bitResolution,
									  IoPortId clearPort,
									  UINT32 clearPin)
{
	this->Initialize(spi, referenceVoltage, bitResolution, clearPort, clearPin);
}

/*! \brief Default Destructor
 */
Dac8568C::~Dac8568C() { }

/*! \brief Sets the reference voltage for the DAC outpts.
 *
 * Sets the reference voltage for the DAC outpts.
 *
 * @param referenceVoltage Positive reference voltage
 */
void Dac8568C::SetReferenceVoltage(float referenceVoltage)
{
	this->_referenceVoltage = referenceVoltage;
}

/*! \brief Initializes a new instance of the DigitalAnalogConverter class.
 *
 * Initializes a new instance of the DigitalAnalogConverter class.
 *
 * @param spi Spi device
 * @param referenceVoltage DAC reference voltage
 * @param bitResolution Bit resolution of DAC
 * @param clearPort IO Port used for !Clear
 * @param clearPin IO Pin used for !Clear
 */
void Dac8568C::Initialize(
								Spi *spi,
								float referenceVoltage,
								unsigned char bitResolution,
								IoPortId clearPort,
								UINT32 clearPin)
{
	this->_spi = spi;
	this->_referenceVoltage = referenceVoltage;
	this->_quantizationLevels = (1 << bitResolution);
	this->_clearPort = clearPort;
	this->_clearPin = clearPin;

	PORTSetPinsDigitalOut(this->_clearPort, this->_clearPin);
	PORTSetBits(this->_clearPort, this->_clearPin);

	// Set up DAC
	this->Reset();
	this->Clear(0);
	this->PowerDown(false);
}

/*! \brief Sets the specified channel to the given value and updates the
 * channel if requested.
 *
 * @param channels
 * @param value
 * @param update
 */
void Dac8568C::Write(unsigned char channels, float value, bool update)
{
	UINT32_VAL command;
	UINT32_VAL val;
	command.Val = 0;
	val.Val = 0;
	command.v[3] = update ? 3 : 0;
	command.v[2] = (channels << 4) & 0xF0;
	float dacCode = (unsigned short int) ((float)(value * _quantizationLevels) / (float)(_referenceVoltage * 2.0f));
	printf("dacCode=%f\r\n", dacCode);
	double step1 = (double)value * (double)_quantizationLevels;
	double step2 = (double)_referenceVoltage * (double)2.0;

	val.Val = value > _referenceVoltage ?
			0xFFFF :
			(unsigned short int) ((float)(value * _quantizationLevels) / (float)(_referenceVoltage * 2.0f));
	command.Val |= (val.Val << 4) & 0x000FFFF0;

	_spi->ChipSelect(true);
	_spi->Write(command.v[3]);
	_spi->Write(command.v[2]);
	_spi->Write(command.v[1]);
	_spi->Write(command.v[0]);
	_spi->ChipSelect(false);
}

/*! \brief Resets the DAC
 */
void Dac8568C::Reset()
{
	UINT32_VAL command;
	command.Val = 0x07000000;
	_spi->ChipSelect(true);
	_spi->Write(command.v[3]);
	_spi->Write(command.v[2]);
	_spi->Write(command.v[1]);
	_spi->Write(command.v[0]);
	_spi->ChipSelect(false);
}

/*! \brief Updates the requested DAC channels
 *
 * @param channels
 */
void Dac8568C::Update(unsigned char channels) { }

/*! \brief Sets all DAC channels to zero, mid, or full output
 *
 * @param value
 */
void Dac8568C::Clear(unsigned char value)
{
	UINT32_VAL command;
	switch (value)
	{
		case 0:
			command.Val = 0x05000000;
			_spi->ChipSelect(true);
			_spi->Write(command.v[3]);
			_spi->Write(command.v[2]);
			_spi->Write(command.v[1]);
			_spi->Write(command.v[0]);
			_spi->ChipSelect(false);
			break;
		case 1:
			break;
		case 2:
			break;

	}
}

/*! \brief Controls the power of the DAC turning it on or off.
 *
 * @param isNotPowered
 */
void Dac8568C::PowerDown(bool isNotPowered)
{
	UINT32_VAL command;
	if (isNotPowered)
	{
	}
	else
	{
		command.Val = 0x040000FF;
		// Power On DACs
		_spi->ChipSelect(true);
		_spi->Write(command.v[3]);
		_spi->Write(command.v[2]);
		_spi->Write(command.v[1]);
		_spi->Write(command.v[0]);
		_spi->ChipSelect(false);
	}
}
